package ca.uqac.dim.turtledb.querytranslator;

import ca.uqac.dim.turtledb.*;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * User: Damien Cavaillès
 * Date: 12-11-24
 * Time: 14:54
 */
public class QueryTranslator {

    public static final String SQL_KEYWORD_SELECT = "SELECT";
    public static final String SQL_KEYWORD_WHERE = "WHERE";
    public static final String SQL_KEYWORD_FROM = "FROM";

    public static void test() {
        System.out.println("PRELIMINARY TEST\n");
        ConditionStatementParser.test();

        System.out.println("\nEND OF PRELIMINARY TEST\n");


        System.out.println("TEST 1 -> SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) WHERE pouet = tortue AND ( tortue = toto OR tortue = 3) ");
        Relation relation = QueryTranslator.translate("SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) WHERE pouet = tortue AND ( tortue = toto OR tortue = 3)");
 //       System.out.println(relation);
        System.out.println("FIN TEST 1\n");

        System.out.println("TEST 2 -> SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) WHERE pouet = tortue AND ( tortue = toto OR tortue = 3 AND tortue = 4) AND Tortue = carapace");
        relation = QueryTranslator.translate("SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) WHERE pouet = tortue AND ( tortue = toto OR tortue = 3 AND tortue = 4) AND Tortue = carapace");
 //       System.out.println(relation);
        System.out.println("FIN TEST 2\n");

        System.out.println("TEST 3 -> SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) , there, there WHERE pouet = tortue AND ( tortue = toto OR tortue = 3 AND tortue = 4) AND Tortue = carapace");
        relation = QueryTranslator.translate("SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) , there, there  WHERE pouet = tortue AND ( tortue = toto OR tortue = 3 AND tortue = 4) AND Tortue = carapace");
        //       System.out.println(relation);
        System.out.println("FIN TEST 3\n");

        System.out.println("TEST 4 -> SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) on there.there = EE , there, there WHERE pouet = tortue AND ( tortue = toto OR tortue = 3 AND tortue = 4) AND Tortue = carapace");
        relation = QueryTranslator.translate("SELECT Pouet, pouet , pouet FROM THere, there , there, (there , there) join (there , there) on there.there = EE , there, there  WHERE pouet = tortue AND ( tortue = toto OR tortue = 3 AND tortue = 4) AND Tortue = carapace");
        //       System.out.println(relation);
        System.out.println("FIN TEST 4\n");
    }


    public static Relation translate(String q) {
        //First Split by Space and coma
        List<String> splittedBySpace = Arrays.asList(q.split("[\\s]\\s*"));

        //First Check it's a SELECT
        if (splittedBySpace.get(0).equalsIgnoreCase(SQL_KEYWORD_SELECT)) {
            //Look for Base Relation

            // get FROM Statement
            List<String> fromStatement = new LinkedList<String>();
            int i = 1;
            while (i < splittedBySpace.size() && !splittedBySpace.get(i).equalsIgnoreCase(SQL_KEYWORD_FROM))
                i++;
            while (i < splittedBySpace.size() && !splittedBySpace.get(i).equalsIgnoreCase(SQL_KEYWORD_FROM) && !splittedBySpace.get(i).equalsIgnoreCase(SQL_KEYWORD_WHERE) && !splittedBySpace.get(i).equalsIgnoreCase(SQL_KEYWORD_SELECT)) {
                fromStatement.add(splittedBySpace.get(i));
                i++;
            }

            return new Projection(makeOutputSchema(splittedBySpace), makeSelection(splittedBySpace));

        } else {
            throw new NotImplementedException();
        }
    }

    private static Selection makeSelection(List<String> splittedQuery) {
        Selection selection = new Selection(makeWhereCondition(splittedQuery), makeRawRelation(splittedQuery));
        return selection;
    }

    private static Condition makeWhereCondition(List<String> splittedQuery) {
        return new ConditionStatementParser(getSplittedWhereStatement(splittedQuery)).process();
    }

    private static List<String> getSplittedWhereStatement(List<String> splittedQuery) {
        List<String> splittedWhereStatement = new LinkedList<String>();
        int i = 0;
        //Parcourir jusqu'au Where
        while (i < splittedQuery.size() && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_WHERE))
            i++;
        //Depasser le Where
        i++;
        //Processing !
        while (i < splittedQuery.size() && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_FROM) && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_SELECT)) {
            splittedWhereStatement.add(splittedQuery.get(i));
            i++;
        }
        return splittedWhereStatement;
    }

    private static Relation makeRawRelation(List<String> splittedQuery) {
        return new FromStatementParser(getSplittedFromStatement(splittedQuery)).process();
    }

    private static List<String> getSplittedFromStatement(List<String> splittedQuery) {
        List<String> splittedFromStatement = new LinkedList<String>();
        int i = 0;
        //Parcourir jusqu'au FROM
        while (i < splittedQuery.size() && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_FROM))
            i++;
        //Depasser le FROM
        i++;
        //Processing !
        while (i < splittedQuery.size() && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_WHERE)) {
            splittedFromStatement.add(splittedQuery.get(i));
            i++;
        }
        return splittedFromStatement;
    }

    private static Schema makeOutputSchema(List<String> splittedQuery) {
        String selectStatement = getSelectStatementFromSplittedQuery(splittedQuery);
        return new Schema(selectStatement);


    }

    private static String getSelectStatementFromSplittedQuery(List<String> splittedQuery) {
        int i = 0;
        String selectStatement = "";
        while (i < splittedQuery.size() && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_SELECT)) {

            i++;
        }
        ;
        i++;
        while (i < splittedQuery.size() && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_FROM) && !splittedQuery.get(i).equalsIgnoreCase(SQL_KEYWORD_WHERE)) {

            selectStatement = selectStatement.concat(" " + splittedQuery.get(i));
            i++;
        }

        return selectStatement;
    }


}
